#include "stdafx.h"
#include "Scene.h"

#include "CollisionComponent.h"
#include "GameObject.h"
#include "GraphicsComponent.h"
#include "SteeringComponent.h"
#include "TransformComponent.h"

//TODO: For the moment the scene class is acting as a factory for different scene elements.
//We can try to make subclasses of GameObject that act as their own factories (build up their own set of components)

namespace Cinetic
{

	std::weak_ptr<GameObject> Scene::add_static_model( Ogre::String mesh_name )
	{
		auto go = std::make_shared<GameObject>();
		go->add_component(std::make_shared<TransformComponent>(go));
        auto graphics = std::make_shared<GraphicsComponent>(go);
        graphics->set_mesh(mesh_name);
		go->add_component(graphics);
		go->add_component(std::make_shared<CollisionComponent>(go));

        GameObject::ComponentChangedDelegate added_d;
        added_d.Bind<Scene, &Scene::on_game_object_component_added>(this);
        go->ComponentAdded += added_d;

        GameObject::ComponentChangedDelegate removed_d;
        removed_d.Bind<Scene, &Scene::on_game_object_component_removed>(this);
        go->ComponentRemoved += removed_d;

		m_game_objects.push_back(go);

        for (auto it = m_observers.begin(); it != m_observers.end(); it++) {
            (*it)->on_game_object_added(go);
        }

		return go;
	}

	std::weak_ptr<GameObject> Scene::add_actor( Ogre::String mesh_name )
	{
        return std::weak_ptr<GameObject>();
	}

    void Scene::attach( SceneObserver* observer )
    {
        auto it = std::find(m_observers.begin(), m_observers.end(), observer);
        if (it == m_observers.end()) {
            m_observers.push_back(observer);
            for ( auto it = m_game_objects.begin(); it != m_game_objects.end(); it++ ) {
                observer->on_game_object_added(*it);
            }
        }
    }

    void Scene::detach( SceneObserver* observer )
    {
        auto it = std::find(m_observers.begin(), m_observers.end(), observer);
        if (it != m_observers.end()) {
            m_observers.erase(it);
        }
    }

    void Scene::on_game_object_component_added( std::weak_ptr<GameObject> go, std::weak_ptr<Component> comp )
    {
        for (auto it = m_observers.begin(); it != m_observers.end(); it++) {
            (*it)->on_component_added(go, comp);
        }
    }

    void Scene::on_game_object_component_removed( std::weak_ptr<GameObject> go, std::weak_ptr<Component> comp )
    {
        for (auto it = m_observers.begin(); it != m_observers.end(); it++) {
            (*it)->on_component_removed(go, comp);
        }
    }

}